package com.itheima.aop;

import com.itheima.mapper.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.utils.CurrentHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.logging.LogRecord;

@Aspect
@Component
@Slf4j
public class OperateLogAspect {

    // 注入 Mapper 用于持久化日志
    @Autowired
    private OperateLogMapper operateLogMapper;

    // 假设通过 ThreadLocal 获取当前登录用户 ID
    @Autowired
    private EmployeeHolder employeeHolder; // 示例：封装了当前线程的用户信息

    // 定义切点：controller包下的所有方法
    @Pointcut("execution(* com.itheima.controller..*.*(..))")
    public void logPointCut() {
    }

    // 环绕通知，记录完整操作日志
    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 可以加上判断是否有 @LogRecord 注解才记录日志
        if (!method.isAnnotationPresent((Class<? extends Annotation>) LogRecord.class)) {
            return joinPoint.proceed(); // 不记录日志直接放行
        }

        Object result = null;
        try {
            // 执行原方法
            result = joinPoint.proceed();
        } finally {
            long costTime = System.currentTimeMillis() - startTime;

            // 构建日志实体
            OperateLog operateLog = new OperateLog();
            operateLog.setOperateEmpId(employeeHolder.getCurrentEmployeeId()); // 获取当前用户ID
            operateLog.setOperateTime(LocalDateTime.now());
            operateLog.setClassName(joinPoint.getTarget().getClass().getName());
            operateLog.setMethodName(method.getName());
            operateLog.setMethodParams(Arrays.toString(joinPoint.getArgs())); // 参数
            operateLog.setReturnValue(result != null ? result.toString() : "null");
            operateLog.setCostTime(costTime);

            // 异步保存日志，避免影响主流程性能
            new Thread(() -> {
                try {
                    operateLogMapper.insert(operateLog);
                } catch (Exception e) {
                    log.error("日志插入失败: ", e);
                }
            }).start();
        }
        private Integer getCurrentEmployeeId() {
            return CurrentHolder.getCurrentId();
        }
    }
}